import { getBuildingConfig, getUnitConfig, MapSettings, ResourceConfig, SplashDamageRatio, BasePositionConfigs } from '../../../battle/Const';
import { CommandType, EntityType, PlayerType, UnitType } from '../../../battle/Enums';
import { BuildingModel, CommandParam, CommandParamMap, UnitModel } from '../../../battle/Model';
import { PlayerStats } from './PlayerStats';
import { LOG } from '../../../ConsoleLogCtrl';

/**
 * 玩家统计数据管理器
 * 管理所有玩家的统计数据
 */
export class PlayerStatsManager {
    private static instance: PlayerStatsManager = null;
    private players: Map<string, PlayerStats> = new Map();

    private constructor() {}

    /**
     * 获取玩家统计数据管理器单例
     */
    public static getInstance(): PlayerStatsManager {
        if (!PlayerStatsManager.instance) {
            PlayerStatsManager.instance = new PlayerStatsManager();
        }
        return PlayerStatsManager.instance;
    }

    /**
     * 重置玩家统计数据管理器
     */
    public reset(): void {
        this.players.clear();
    }

    /**
     * 初始化玩家统计数据
     * @param playerId 玩家ID
     * @param color 玩家颜色
     * @param startPosition 起始位置
     * @param playerType 玩家类型
     */
    public initPlayerStats(
        playerId: string,
        color: string,
        startPosition: { x: number; y: number },
        playerType: PlayerType
    ): PlayerStats {
        const playerStats = new PlayerStats(playerId, color, startPosition, playerType);
        this.players.set(playerId, playerStats);
        return playerStats;
    }

    /**
     * 获取玩家统计数据
     * @param playerId 玩家ID
     */
    public getPlayerStats(playerId: string): PlayerStats | undefined {
        return this.players.get(playerId);
    }

    /**
     * 获取所有玩家统计数据
     */
    public getAllPlayerStats(): PlayerStats[] {
        return Array.from(this.players.values());
    }

    /**
     * 处理更新玩家统计数据
     * @param command 战斗命令
     */
    public handleCommandStats(command: CommandParam<keyof CommandParamMap>): void {
        if (!command) return;

        if (command.type == CommandType.init) {
            this.initCommandStast(command as CommandParam<CommandType.init>);
            return;
        }

        const playerId = command.player;
        const playerStats = this.getPlayerStats(playerId);
        if (!playerStats) return;

        // 获取敌方玩家统计数据
        const enemyPlayerStats = this.getEnemyPlayerStats(playerId);

        switch (command.type) {
            case CommandType.move:
                this.moveCommandStast(command as CommandParam<CommandType.move>, playerStats);
                break;
            case CommandType.attack:
                this.attackCommandStast(command as CommandParam<CommandType.attack>, playerStats, enemyPlayerStats);
                break;
            case CommandType.build:
                this.buildCommandStast(command as CommandParam<CommandType.build>, playerStats);
                break;
            case CommandType.swap:
                this.swapCommandStast(command as CommandParam<CommandType.swap>, playerStats);
                break;
            case CommandType.heal:
                this.healCommandStast(command as CommandParam<CommandType.heal>, playerStats);
                break;
            case CommandType.collect:
                this.collectCommandStast(command as CommandParam<CommandType.collect>, playerStats);
                break;
            default:
                break;
        }
    }

    /**
     * 处理初始化命令
     */
    private initCommandStast(command: CommandParam<CommandType.init>): void {
        LOG.log('初始化玩家基础统计数据:', command);
        if (command.type === CommandType.init && command.param) {
            const initParam = command.param;
            initParam.players.forEach((player, index) => {
                let playerType = index === 0 ? PlayerType.PLAYER1 : PlayerType.PLAYER2;
                const color = index === 0 ? MapSettings.playerColors[0] : MapSettings.playerColors[1];
                const startPosition = BasePositionConfigs[initParam.map][index];
                this.initPlayerStats(player, color, startPosition, playerType);
            });
        }
    }

    /**
     * 处理移动命令
     */
    private moveCommandStast(command: CommandParam<CommandType.move>, playerStats: PlayerStats): void {
        const moveParam = command.param;
        const unitId = moveParam.self.id;
        const unit = playerStats.getUnit(unitId);

        if (unit) {
            // 计算新位置（当前位置 + 偏移量）
            unit.position = {
                x: unit.position.x + moveParam.offsetPosition.x,
                y: unit.position.y + moveParam.offsetPosition.y,
            };
        }
    }

    /**
     * 计算溅射目标位置
     * @param targetPosition 被攻击目标的位置
     * @param offsetPosition 攻击方向偏移量
     * @returns 溅射目标位置数组
     */
    private calculateSplashPositions(targetPosition: { x: number; y: number }, offsetPosition: { x: number; y: number }): { x: number; y: number }[] {
        // 根据攻击方向计算溅射目标位置
        // 如果攻击方向是(1,0)，则溅射位置是(1,1)和(1,-1)
        // 如果攻击方向是(0,1)，则溅射位置是(1,1)和(-1,1)
        // 如果攻击方向是(-1,0)，则溅射位置是(-1,1)和(-1,-1)
        // 如果攻击方向是(0,-1)，则溅射位置是(1,-1)和(-1,-1)
        const splashPositions: { x: number; y: number }[] = [];

        if (offsetPosition.x !== 0) {
            // 水平攻击，溅射到上下两个位置
            splashPositions.push(
                { x: targetPosition.x, y: targetPosition.y + 1 },
                { x: targetPosition.x, y: targetPosition.y - 1 }
            );
        } else if (offsetPosition.y !== 0) {
            // 垂直攻击，溅射到左右两个位置
            splashPositions.push(
                { x: targetPosition.x + 1, y: targetPosition.y },
                { x: targetPosition.x - 1, y: targetPosition.y }
            );
        }

        return splashPositions;
    }

    /**
     * 处理溅射伤害统计
     * @param attacker 攻击者
     * @param targetPosition 目标位置
     * @param offsetPosition 攻击方向偏移量
     * @param playerStats 攻击者统计数据
     * @param enemyPlayerStats 敌方统计数据
     */
    private applySplashDamageStats(
        attacker: UnitModel | BuildingModel,
        targetPosition: { x: number; y: number },
        offsetPosition: { x: number; y: number },
        playerStats: PlayerStats,
        enemyPlayerStats: PlayerStats
    ): void {
        const splashDamage = Math.floor(attacker.attack * SplashDamageRatio);

        // 计算溅射目标位置
        const splashPositions = this.calculateSplashPositions(targetPosition, offsetPosition);

        // 对溅射位置的敌方单位造成伤害统计
        for (const splashPos of splashPositions) {
            // 查找溅射位置的敌方单位
            const splashUnit = enemyPlayerStats.getAllUnits().find(unit => 
                unit.position.x === splashPos.x && unit.position.y === splashPos.y
            );

            if (splashUnit) {
                // 计算溅射伤害
                const newHp = Math.max(0, splashUnit.hp - splashDamage);
                const actualDamage = splashUnit.hp - newHp;

                // 更新统计数据
                playerStats.addDamageDealt(actualDamage);
                enemyPlayerStats.addDamageReceived(actualDamage);

                if (newHp <= 0) {
                    // 溅射导致单位死亡
                    enemyPlayerStats.removeUnit(splashUnit.id);
                    playerStats.addKill();
                    enemyPlayerStats.addDeath();

                    // 给击杀方增加击杀奖励
                    const unitConfig = getUnitConfig(splashUnit.type);
                    if (unitConfig && unitConfig.killedAward) {
                        playerStats.addRmb(unitConfig.killedAward);
                    }
                } else {
                    // 更新血量
                    enemyPlayerStats.updateUnitHealth(splashUnit.id, newHp);
                }
            }
        }
    }

    /**
     * 处理攻击命令
     */
    private attackCommandStast(command: CommandParam<CommandType.attack>, playerStats: PlayerStats, enemyPlayerStats: PlayerStats): void {
        const attackParam = command.param;
        const attackerId = attackParam.self.id;
        const attackerType = attackParam.self.type;
        const targetId = attackParam.target.id;
        const targetType = attackParam.target.type;

        if (!enemyPlayerStats) return;

        // 获取攻击者的攻击力
        let attackPower = 0;
        if (attackerType === EntityType.unit) {
            const attackerUnit = playerStats.getUnit(attackerId);
            if (attackerUnit) {
                attackPower = attackerUnit.attack;
            }
        } else if (attackerType === EntityType.building) {
            const attackerBuilding = playerStats.getBuilding(attackerId);
            if (attackerBuilding) {
                attackPower = attackerBuilding.attack;
            }
        }

        if (attackPower <= 0) return;

        // 检查是否需要应用溅射伤害（在处理主要伤害之前）
        let shouldApplySplash = false;
        let splashTargetPosition: { x: number; y: number } | null = null;
        let splashAttacker: UnitModel | null = null;

        if (attackerType === EntityType.unit && targetType === EntityType.unit) {
            const attackerUnit = playerStats.getUnit(attackerId);
            const targetUnit = enemyPlayerStats.getUnit(targetId);
            if (attackerUnit && attackerUnit.type === UnitType.soldier && targetUnit) {
                shouldApplySplash = true;
                splashTargetPosition = { ...targetUnit.position };
                splashAttacker = attackerUnit;
            }
        }

        // 处理对单位的攻击
        if (targetType === EntityType.unit) {
            const targetUnit = enemyPlayerStats.getUnit(targetId);
            if (targetUnit) {
                const newHp = Math.max(0, targetUnit.hp - attackPower);
                const actualDamage = targetUnit.hp - newHp;

                // 更新统计数据
                playerStats.addDamageDealt(actualDamage);
                enemyPlayerStats.addDamageReceived(actualDamage);

                if (newHp <= 0) {
                    // 单位死亡
                    enemyPlayerStats.removeUnit(targetId);
                    playerStats.addKill();
                    enemyPlayerStats.addDeath();

                    // 给击杀方增加击杀奖励
                    const unitConfig = getUnitConfig(targetUnit.type);
                    if (unitConfig && unitConfig.killedAward) {
                        playerStats.addRmb(unitConfig.killedAward);
                    }
                } else {
                    // 更新血量
                    enemyPlayerStats.updateUnitHealth(targetId, newHp);
                }
            }
        }
        // 处理对建筑的攻击
        else if (targetType === EntityType.building) {
            const targetBuilding = enemyPlayerStats.getBuilding(targetId);
            if (targetBuilding) {
                const newHp = Math.max(0, targetBuilding.hp - attackPower);
                const actualDamage = targetBuilding.hp - newHp;

                // 更新统计数据
                playerStats.addDamageDealt(actualDamage);
                enemyPlayerStats.addDamageReceived(actualDamage);

                if (newHp <= 0) {
                    // 建筑被摧毁
                    enemyPlayerStats.removeBuilding(targetId);
                    playerStats.addKill(); // 建筑摧毁也算击杀

                    // 给击杀方增加击杀奖励
                    const buildingConfig = getBuildingConfig(targetBuilding.type);
                    if (buildingConfig && buildingConfig.killedAward) {
                        playerStats.addRmb(buildingConfig.killedAward);
                    }
                } else {
                    // 更新血量
                    enemyPlayerStats.updateBuildingHealth(targetId, newHp);
                }
            }
        }

        // 应用溅射伤害统计（使用之前保存的信息）
        if (shouldApplySplash && splashAttacker && splashTargetPosition) {
            this.applySplashDamageStats(
                splashAttacker,
                splashTargetPosition,
                attackParam.offsetPosition,
                playerStats,
                enemyPlayerStats
            );
        }
    }

    /**
     * 处理建造命令
     */
    private buildCommandStast(command: CommandParam<CommandType.build>, playerStats: PlayerStats): void {
        const buildParam = command.param;
        const buildingId = buildParam.target.id;
        const buildingType = buildParam.target.utype;

        let position = {
            x: buildParam.offsetPosition.x,
            y: buildParam.offsetPosition.y,
        };

        // 获取建造者单位
        const builderId = buildParam.self.id;
        const builder = playerStats.getUnit(builderId);

        // 计算建筑的实际位置（建造者位置 + 偏移量）
        if (builder) {
            position.x = builder.position.x + position.x;
            position.y = builder.position.y + position.y;
        }

        // 获取建筑配置
        const buildingConfig = getBuildingConfig(buildingType);

        // 扣除建造成本
        const cost = buildingConfig.cost;
        if (cost > 0) {
            // 直接扣除资源
            playerStats.addRmb(-cost);
        }

        // 创建建筑模型
        const building: BuildingModel = {
            id: buildingId,
            type: buildingType,
            player: command.player,
            hp: buildingConfig.hp,
            attack: buildingConfig.attack,
            position: position,
        };

        // 添加建筑到玩家统计数据
        playerStats.addBuilding(building);
    }

    /**
     * 处理生产单位命令
     */
    private swapCommandStast(command: CommandParam<CommandType.swap>, playerStats: PlayerStats): void {
        const swapParam = command.param;
        const unitId = swapParam.target.id;
        const unitType = swapParam.target.utype;

        // 获取生产建筑
        const buildingId = swapParam.self.id;
        const building = playerStats.getBuilding(buildingId);
        if (!building) return;

        // 计算单位的实际位置（建筑位置 + 偏移量）
        const position = {
            x: building.position.x + swapParam.offsetPosition.x,
            y: building.position.y + swapParam.offsetPosition.y,
        };

        // 获取单位配置
        const unitConfig = getUnitConfig(unitType);

        // 扣除生产成本
        const cost = unitConfig.cost;
        if (cost > 0) {
            // 直接扣除资源
            playerStats.addRmb(-cost);
        }

        // 创建单位模型
        const unit: UnitModel = {
            id: unitId,
            type: unitType,
            player: command.player,
            hp: unitConfig.hp,
            attack: unitConfig.attack,
            speed: unitConfig.speed,
            position: position,
        };

        // 添加单位到玩家统计数据
        playerStats.addUnit(unit);
    }

    /**
     * 处理治疗命令
     */
    private healCommandStast(command: CommandParam<CommandType.heal>, playerStats: PlayerStats): void {
        const healParam = command.param;
        const targetId = healParam.target.id;

        // 获取治疗单位
        const healerUnit = playerStats.getUnit(healParam.self.id);
        if (!healerUnit) return;

        // 获取目标单位
        const targetUnit = playerStats.getUnit(targetId);
        if (!targetUnit) return;

        // 计算治疗量
        const healAmount = healerUnit.attack;

        // 更新目标单位血量（不超过单位最大血量）
        const maxHp = getUnitConfig(targetUnit.type).hp;
        const newHp = Math.min(targetUnit.hp + healAmount, maxHp);

        // 计算实际治疗量
        const actualHealing = newHp - targetUnit.hp;

        // 增加治疗者的治疗总量统计
        playerStats.addHealing(actualHealing);

        playerStats.updateUnitHealth(targetId, newHp);
    }

    /**
     * 处理采集命令
     */
    private collectCommandStast(command: CommandParam<CommandType.collect>, playerStats: PlayerStats): void {
        const collectParam = command.param;
        const resourceType = collectParam.target.utype;

        // 获取采集单位
        const collectorUnit = playerStats.getUnit(collectParam.self.id);
        if (!collectorUnit) return;

        // 获取资源配置
        const resourceConfig = ResourceConfig[resourceType];
        if (!resourceConfig) return;

        // 计算采集量
        const collectAmount = resourceConfig.value;

        // 增加玩家资源
        playerStats.addRmb(collectAmount);
    }

    /**
     * 获取敌方玩家统计数据
     * @param playerId 当前玩家ID
     */
    public getEnemyPlayerStats(playerId: string): PlayerStats | undefined {
        for (const [id, stats] of this.players.entries()) {
            if (id !== playerId) {
                return stats;
            }
        }
        return undefined;
    }

    /**
     * 获取敌方生产单位数量
     * @param playerId 当前玩家ID
     */
    public getEnemyProducedUnitsCount(playerId: string): number {
        const enemyStats = this.getEnemyPlayerStats(playerId);
        return enemyStats ? enemyStats.getProducedUnitsCount() : 0;
    }

    /**
     * 获取敌方死亡单位数量
     * @param playerId 当前玩家ID
     */
    public getEnemyDeadUnitsCount(playerId: string): number {
        const enemyStats = this.getEnemyPlayerStats(playerId);
        return enemyStats ? enemyStats.getDeadUnitsCount() : 0;
    }

    /**
     * 获取敌方存活单位数量
     * @param playerId 当前玩家ID
     */
    public getEnemyAliveUnitsCount(playerId: string): number {
        const enemyStats = this.getEnemyPlayerStats(playerId);
        return enemyStats ? enemyStats.getAliveUnitsCount() : 0;
    }

    /**
     * 获取敌方构建建筑数量
     * @param playerId 当前玩家ID
     */
    public getEnemyBuiltBuildingsCount(playerId: string): number {
        const enemyStats = this.getEnemyPlayerStats(playerId);
        return enemyStats ? enemyStats.getBuiltBuildingsCount() : 0;
    }

    /**
     * 获取敌方被摧毁建筑数量
     * @param playerId 当前玩家ID
     */
    public getEnemyDestroyedBuildingsCount(playerId: string): number {
        const enemyStats = this.getEnemyPlayerStats(playerId);
        return enemyStats ? enemyStats.getDestroyedBuildingsCount() : 0;
    }

    /**
     * 获取敌方现存建筑数量
     * @param playerId 当前玩家ID
     */
    public getEnemyExistingBuildingsCount(playerId: string): number {
        const enemyStats = this.getEnemyPlayerStats(playerId);
        return enemyStats ? enemyStats.getExistingBuildingsCount() : 0;
    }

    /**
     * 获取敌方基地血量
     * @param playerId 当前玩家ID
     */
    public getEnemyBaseHealth(playerId: string): number {
        const enemyStats = this.getEnemyPlayerStats(playerId);
        return enemyStats ? enemyStats.getBaseHealth() : 0;
    }

    /**
     * 获取玩家造成的总伤害
     * @param playerId 玩家ID
     */
    public getPlayerTotalDamageDealt(playerId: string): number {
        const playerStats = this.getPlayerStats(playerId);
        return playerStats ? playerStats.getTotalDamageDealt() : 0;
    }

    /**
     * 获取玩家受到的总伤害
     * @param playerId 玩家ID
     */
    public getPlayerTotalDamageReceived(playerId: string): number {
        const playerStats = this.getPlayerStats(playerId);
        return playerStats ? playerStats.getTotalDamageReceived() : 0;
    }

    /**
     * 获取玩家治疗总量
     * @param playerId 玩家ID
     */
    public getPlayerTotalHealing(playerId: string): number {
        const playerStats = this.getPlayerStats(playerId);
        return playerStats ? playerStats.getTotalHealing() : 0;
    }

    /**
     * 获取玩家击杀数
     * @param playerId 玩家ID
     */
    public getPlayerKills(playerId: string): number {
        const playerStats = this.getPlayerStats(playerId);
        return playerStats ? playerStats.getKills() : 0;
    }

    /**
     * 获取玩家死亡数
     * @param playerId 玩家ID
     */
    public getPlayerDeaths(playerId: string): number {
        const playerStats = this.getPlayerStats(playerId);
        return playerStats ? playerStats.getDeaths() : 0;
    }

    /**
     * 获取敌方造成的总伤害
     * @param playerId 当前玩家ID
     */
    public getEnemyTotalDamageDealt(playerId: string): number {
        const enemyStats = this.getEnemyPlayerStats(playerId);
        return enemyStats ? enemyStats.getTotalDamageDealt() : 0;
    }

    /**
     * 获取敌方受到的总伤害
     * @param playerId 当前玩家ID
     */
    public getEnemyTotalDamageReceived(playerId: string): number {
        const enemyStats = this.getEnemyPlayerStats(playerId);
        return enemyStats ? enemyStats.getTotalDamageReceived() : 0;
    }

    /**
     * 获取敌方治疗总量
     * @param playerId 当前玩家ID
     */
    public getEnemyTotalHealing(playerId: string): number {
        const enemyStats = this.getEnemyPlayerStats(playerId);
        return enemyStats ? enemyStats.getTotalHealing() : 0;
    }

    /**
     * 获取敌方击杀数
     * @param playerId 当前玩家ID
     */
    public getEnemyKills(playerId: string): number {
        const enemyStats = this.getEnemyPlayerStats(playerId);
        return enemyStats ? enemyStats.getKills() : 0;
    }

    /**
     * 获取敌方死亡数
     * @param playerId 当前玩家ID
     */
    public getEnemyDeaths(playerId: string): number {
        const enemyStats = this.getEnemyPlayerStats(playerId);
        return enemyStats ? enemyStats.getDeaths() : 0;
    }

}
